package com.hospital.common.core.utils;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.digest.SM3;
import cn.hutool.crypto.symmetric.SM4;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * <p>Description: 定点机构调用平台端的测试用例</p>
 *
 * @author Junpengzhou
 * @version 1.0.0
 * @since 2022.07.20 08:15
 */
@Slf4j
@Component
public class Sm3Demo {

    /**
     * 定点机构调用平台：
     *     签名：SM3，加密：SM4
     *     测试应用ID：1FM99V9JP0009A23A8C00000D445BA03
     *     测试应用秘钥：1FM99V9JM00N9A23A8C000003F4B7C32
     *     正式应用ID：B7103B095AAA4E9FA47AFBB7A91E9CB0
     *     正式应用秘钥：BEE52A207E014E419BEAE865968BFD7B
     */

    private static String APP_ID ;
    private static  String APP_SECRET;

    @Value("${insuranceconfig.appIdHis}")
    public void setAppId(String appIdHis) {
        Sm3Demo.APP_ID = appIdHis;
    }
    @Value("${insuranceconfig.appSecretHis}")
    public void setAppSecret(String appSecretHis) {
        Sm3Demo.APP_SECRET = appSecretHis;
    }

    public static Map<String, String> encAndSingHis(String plainStr, JSONObject responseJsonObj,String appId,String appSecret) {
        Map<String, String> map = new HashMap<>();
        // 加密密文
        String encryptData = encData(plainStr,appId,appSecret);
//        log.info("密文:{}", encryptData);
        map.put("encryptData", encryptData);
        String beSignText = getBeSignText(responseJsonObj, appSecret);
        SM3 sm3 = SmUtil.sm3();
        byte[] digest = sm3.digest(beSignText.getBytes());
        String sign = Base64.getUrlEncoder().encodeToString(digest);
//        log.info("签名:{}", sign);
        map.put("signData", sign);
//        log.info("===============================================================入参加密结束===============================================================");
        return map;
    }

    public static JSONObject denc(JSONObject originResponse,String appId,String appSecret) {
        JSONObject responseJsonObj = getDecBody(originResponse,appId,appSecret);
        // 加密密文
        try {
            String beSignText = getBeSignText(responseJsonObj, appSecret);
            SM3 sm3 = SmUtil.sm3();
            byte[] digest = sm3.digest(beSignText.getBytes());
            String sign = Base64.getUrlEncoder().encodeToString(digest);
            String sign1 = originResponse.getString("sign");
            if (sign.equals(sign1)) {
                responseJsonObj.put("signCheck", true);
            } else {
                responseJsonObj.put("signCheck", false);
            }
        } catch (Exception e) {
            responseJsonObj.put("signCheck", false);
        }
//        log.info("===============================================================出参解密验签结束===============================================================");
        return responseJsonObj;
    }


    private static String encData(String plainStr,String appId,String appSecret) {
//        log.info("应用ID:{}", APP_ID);
//        log.info("应用APP_SECRET:{}", APP_SECRET);
//        log.info("明文:{}", plainStr);
        String firstKey = appId.substring(0, 16);
//        log.info("截取前16bit后的APP_ID:{}", firstKey);
        SM4 sm4 = new SM4(Mode.ECB, Padding.PKCS5Padding, StrUtil.utf8Bytes(firstKey));
        String encKey = sm4.encryptHex(appSecret);
//        log.info("加密后的新秘钥:{}", encKey);
        String newKey = encKey.substring(0, 16);
//        log.info("加密后的新秘钥（截取16位数）:{}", newKey);
        SM4 newSm4 = new SM4(Mode.ECB, Padding.PKCS5Padding, StrUtil.utf8Bytes(newKey));
        byte[] encrypt = newSm4.encrypt(plainStr);
        String encData = Base64.getUrlEncoder().encodeToString(encrypt);
//        log.info("加密后密文:{}", encData);
        return encData;
    }

    private static JSONObject getDecBody(JSONObject requestBodyObj,String appId,String appSecret) {
        boolean appId1 = requestBodyObj.containsKey("appId");
        boolean encryptData = requestBodyObj.containsKey("encryptData");
        String plainData = null;
        if (appId1) {
            String chnlIdSrc = requestBodyObj.getString("appId");
            appId = StringUtil.isEmpty(chnlIdSrc) ? appId: chnlIdSrc ;
//            log.info("应用ID:{}", appId);
            if (encryptData) {
                String encStr = requestBodyObj.getString("encryptData");
//                log.info("密文:{}", encStr);
                String firstKey = appId.substring(0, 16);
//                log.info("截取前16位后的APP_ID:{}", firstKey);
                SM4 sm4 = new SM4(Mode.ECB, Padding.PKCS5Padding, StrUtil.utf8Bytes(firstKey));
                String encKey = sm4.encryptHex(appSecret);
//                log.info("加密后的新秘钥:{}", encKey);
                String newKey = encKey.substring(0, 16);
//                log.info("加密后的新秘钥（截取16位数）:{}", newKey);
                SM4 newSm4 = new SM4(Mode.ECB, Padding.PKCS5Padding, StrUtil.utf8Bytes(newKey));
                plainData = newSm4.decryptStr(encStr);
//                log.info("解密后密文:{}", plainData);
            }
        }
        requestBodyObj.put("param", plainData);
        return requestBodyObj;
    }

    private static String getBeSignText(Map<String, Object> body, String key) {
        TreeMap<Object, Object> bodyTreeMap = new TreeMap<>(body);
        if (CollectionUtil.isEmpty(bodyTreeMap)) {
            return "";
        }
        // 剔除非参签字段
        bodyTreeMap.remove("sign");
        bodyTreeMap.remove("encryptData");
        bodyTreeMap.remove("extra");
        bodyTreeMap.remove("code");
        StringBuilder signData = new StringBuilder();
        bodyTreeMap.forEach((k, v) -> {
            String value;
            if (Objects.isNull(v)) {
                return;
            } else if (v instanceof String) {
                value = (String) v;
            } else if (v instanceof Number) {
                value = StrUtil.str(v, StandardCharsets.UTF_8);
            } else {
                value = JSONObject.toJSONString(v);
            }
            signData.append(k).append("=").append(value).append("&");
        });
        String beSignText = signData.append("key=").append(key).toString();
//        log.info("待签串:{}", beSignText);
        return beSignText;
    }
}
